package httpproxy;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import httpproxy.server.DeniedItem;
import httpproxy.server.ProxyServer;

public class HttpProxyMain 
{
	private Display display = new Display();
	private Shell shell = new Shell(display);
	
	private Text txtChainProxyHost, txtChainProxyPort, txtPort;
	private Button btnSaveConfig, btnShowACL, chkChainProxy;
	private ProxyServer server = null;
	
	private static int serverPort;
	private static boolean _isChainProxy = false;
	private static String _chainProxyHost = "";
	private static int _chainProxyPort = 0;
	private static Properties _configurations = new Properties();
	private static List<DeniedItem> acl = new ArrayList<DeniedItem>();
	private static String executionPath = null;

	public HttpProxyMain()
	{
		//loadProperties();
		loadPropertiesTest();
		loadACLTest();
		
		initComponent();
		shell.setSize(500, 220);
		shell.open();
		while(!shell.isDisposed())
		{
			if(!display.readAndDispatch())
				display.sleep();
		}
		
		display.dispose();
	}

	public void initComponent()
	{
		FormLayout layout = new FormLayout();
		layout.marginHeight = 5;
		layout.marginWidth = 5;
		shell.setText("HTTP Proxy");
		shell.setLayout(layout);
		
		shell.addShellListener(new ShellListener() {

		      public void shellActivated(ShellEvent event) {
		        System.out.println("activate");
		      }

		      public void shellClosed(ShellEvent arg0) {
		    	  saveProperties();
		    	  if(server != null && server.isRunning())
		    		  server.stopServer();
		      }

		      public void shellDeactivated(ShellEvent arg0) {
		      }

		      public void shellDeiconified(ShellEvent arg0) {
		      }

		      public void shellIconified(ShellEvent arg0) {
		      }
		    });
		
		FormData formData = new FormData();
		Label lbPort = new Label(shell, SWT.NONE);
		lbPort.setText("Proxy port: ");
		formData.top = new FormAttachment(shell, 0, SWT.TOP);
		formData.left = new FormAttachment(shell, 5, SWT.FILL);
		lbPort.setLayoutData(formData);
		
		txtPort = new Text(shell, SWT.BORDER);
		formData = new FormData();
		formData.top = new FormAttachment(shell, 0, SWT.TOP);
		formData.left = new FormAttachment(lbPort, 5, SWT.RIGHT);
		//formData.right = new FormAttachment(100, 0);
		//formData.bottom = new FormAttachment(100, 0);
		txtPort.setLayoutData(formData);
		
		Group groupChainProxy = new Group(shell, SWT.NONE);
		groupChainProxy.setLayout(new FormLayout());
		formData = new FormData();
		formData.left = new FormAttachment(0, 5);
		formData.top = new FormAttachment(0, 35);
		formData.right = new FormAttachment(100, -5);
		formData.bottom = new FormAttachment(100, -45);
		groupChainProxy.setLayoutData(formData);
		
		chkChainProxy = new Button(groupChainProxy, SWT.CHECK);
		chkChainProxy.setText("Use chain proxy");
		formData = new FormData();
		formData.top = new FormAttachment(0, 5);
		formData.left = new FormAttachment(0, 5);
		//formData.right = new FormAttachment(100, 0);
		//formData.bottom = new FormAttachment(100, 0);
		chkChainProxy.setLayoutData(formData);
		
		formData = new FormData();
		Label lbchainHost = new Label(groupChainProxy, SWT.NONE);
		lbchainHost.setText("Chain proxy host: ");
		formData.top = new FormAttachment(chkChainProxy, 5, SWT.BOTTOM);
		formData.left = new FormAttachment(chkChainProxy, 0, SWT.LEFT);
		lbchainHost.setLayoutData(formData);
		
		txtChainProxyHost = new Text(groupChainProxy, SWT.BORDER);
		txtChainProxyHost.setSize(txtChainProxyHost.getSize().x, 100);
		formData = new FormData();
		formData.top = new FormAttachment(chkChainProxy, 5, SWT.BOTTOM);
		formData.left = new FormAttachment(lbchainHost, 5, SWT.RIGHT);
		formData.right = new FormAttachment(80, 0);
		//formData.bottom = new FormAttachment(100, 0);
		txtChainProxyHost.setLayoutData(formData);
		
		formData = new FormData();
		Label lbchainPort = new Label(groupChainProxy, SWT.NONE);
		lbchainPort.setText("Chain proxy port: ");
		formData.top = new FormAttachment(txtChainProxyHost, 5, SWT.BOTTOM);
		formData.left = new FormAttachment(chkChainProxy, 0, SWT.LEFT);
		lbchainPort.setLayoutData(formData);
		
		txtChainProxyPort = new Text(groupChainProxy, SWT.BORDER);
		formData = new FormData();
		formData.top = new FormAttachment(txtChainProxyHost, 5, SWT.BOTTOM);
		formData.left = new FormAttachment(lbchainHost, 5, SWT.RIGHT);
		//formData.right = new FormAttachment(100, 0);
		//formData.bottom = new FormAttachment(100, 0);
		txtChainProxyPort.setLayoutData(formData);
		
		//Save Button
		btnSaveConfig = new Button(shell, SWT.TOGGLE);
		btnSaveConfig.setText("Start proxy server");
		formData = new FormData();
		formData.top = new FormAttachment(groupChainProxy, 5, SWT.BOTTOM);
		formData.left = new FormAttachment(groupChainProxy, 0, SWT.LEFT);
		//formData.right = new FormAttachment(100, 0);
		//formData.bottom = new FormAttachment(100, 0);
		btnSaveConfig.setLayoutData(formData);
		
		btnShowACL = new Button(shell, SWT.PUSH);
		btnShowACL.setText("Access control list");
		formData = new FormData();
		formData.top = new FormAttachment(groupChainProxy, 5, SWT.BOTTOM);
		formData.left = new FormAttachment(btnSaveConfig, 5, SWT.RIGHT);
		btnShowACL.setLayoutData(formData);
		
		chkChainProxy.setSelection(_isChainProxy);
		txtPort.setText(serverPort + "");
		txtChainProxyHost.setText(_chainProxyHost);
		txtChainProxyPort.setText(_chainProxyPort+"");
		
		btnSaveConfig.addListener(SWT.Selection, new Listener(){
			public void handleEvent(Event e)
			{
				if(btnSaveConfig.getSelection())
				{
					serverPort = Integer.parseInt(txtPort.getText().trim());
					_isChainProxy = chkChainProxy.getSelection();
					_chainProxyHost = txtChainProxyHost.getText().trim();
					_chainProxyPort = Integer.parseInt(txtChainProxyPort.getText());
					
					if(server == null)
						server = new ProxyServer(serverPort);
					server.start();
					btnSaveConfig.setText("Stop proxy server");
				}
				else
				{
					if(server != null)
					{
						server.stopServer();
						server = null;
					}
					
					btnSaveConfig.setText("Start proxy server");
				}
			}
		});
		
		btnShowACL.addListener(SWT.Selection, new Listener(){
			public void handleEvent(Event e)
			{
				AccessControlList aclUI = new AccessControlList(shell);
			}
		});
	}
	
	public static synchronized String getChainProxyHost() {
		return _chainProxyHost;
	}

	public static synchronized int getChainProxyPort() {
		return _chainProxyPort;
	}

	public static synchronized boolean IsChainProxy()
	{
		return _isChainProxy;
	}
	
	public static synchronized List<DeniedItem> getACL()
	{
		return acl;
	}

	public static synchronized void addDeniedItem(String host, String type)
	{
		DeniedItem addedItm = null;
		
		for(DeniedItem itm:acl)
		{
			if(itm.server.equals(host) && itm.type.endsWith(type))
			{
				return;
			}
		}
		
		addedItm = new DeniedItem(host, type);
		acl.add(addedItm);
	}
	
	public static synchronized void addDeniedItem(DeniedItem item)
	{	
		for(DeniedItem itm:acl)
		{
			if(itm.server.equals(item.server) && itm.type.endsWith(item.type))
			{
				return;
			}
		}
		
		acl.add(item);
	}
	
	public static synchronized void removeDeniedItem(String host, String type)
	{
		for(DeniedItem itm:acl)
		{
			if(itm.server.equals(host) && itm.type.endsWith(type))
			{
				acl.remove(itm);
				return;
			}
		}
	}
	
	public static synchronized void removeDeniedItem(DeniedItem itm)
	{
		acl.remove(itm);
	}
	
	public static synchronized void saveACL()
	{
		String decodedPath = getExecutionPath();
		try {
			FileWriter fw = new FileWriter(String.format("%s/acl.data", decodedPath));
			for(DeniedItem itm:acl)
			{
				fw.write(String.format("%s %s\r\n", itm.server, itm.type));
			}
			fw.flush();
			fw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private static synchronized void saveProperties()
	{
		String decodedPath = getExecutionPath();
		try {
			_configurations.setProperty("proxy.server.port", serverPort+"");
			_configurations.setProperty("isChainProxy", Boolean.toString(_isChainProxy));
			_configurations.setProperty("chain.proxy.host", _chainProxyHost);
			_configurations.setProperty("chain.proxy.port", _chainProxyPort+"");
			
			FileOutputStream fos = new FileOutputStream(String.format("%s/proxy.properties", decodedPath));
			_configurations.store(fos, "");
			FileWriter fw = new FileWriter(String.format("%s/acl.data", decodedPath));
			for(DeniedItem itm:acl)
			{
				fw.write(String.format("%s %s\r\n", itm.server, itm.type));
			}
			fw.flush();
			fw.close();
		}catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static String getProperty(String key)
	{
		return _configurations.getProperty(key);
	}
	
	
	public static String getExecutionPath()
	{
		if(executionPath==null || executionPath.trim().equals(""))
		{
			String path = httpproxy.HttpProxyMain.class.getProtectionDomain().getCodeSource().getLocation().getPath();
			File f = new File(path);
			executionPath = f.getParentFile().getPath();
		}
		return executionPath;
	}
	
	private void loadProperties()
	{
		try{
			String decodedPath = getExecutionPath();
			System.out.println("properties path: " + decodedPath);
			FileInputStream fis = new FileInputStream(String.format("%s/proxy.properties", decodedPath));
			_configurations.load(fis);
			serverPort = Integer.parseInt(_configurations.getProperty("proxy.server.port"));
			_isChainProxy = Boolean.parseBoolean(_configurations.getProperty("isChainProxy"));
			_chainProxyHost = _configurations.getProperty("chain.proxy.host");
			_chainProxyPort = Integer.parseInt(_configurations.getProperty("chain.proxy.port"));
			fis.close();
		}catch(IOException ex)
		{
			ex.printStackTrace();
			System.out.println("System going to be down!");
			System.exit(1);
		}
	}
	
	private void loadPropertiesTest()
	{
		try{
			String path = httpproxy.HttpProxyMain.class.getProtectionDomain().getCodeSource().getLocation().getPath();
			String decodedPath = URLDecoder.decode(path, "UTF-8");
			System.out.println("properties path: " + decodedPath);
			FileInputStream fis = new FileInputStream(String.format("%sproxy.properties", decodedPath));
			_configurations.load(fis);
			serverPort = Integer.parseInt(_configurations.getProperty("proxy.server.port"));
			_isChainProxy = Boolean.parseBoolean(_configurations.getProperty("isChainProxy"));
			_chainProxyHost = _configurations.getProperty("chain.proxy.host");
			_chainProxyPort = Integer.parseInt(_configurations.getProperty("chain.proxy.port"));
			fis.close();
		}catch(IOException ex)
		{
			ex.printStackTrace();
			System.out.println("System going to be down!");
			System.exit(1);
		}
	}
	
	private void loadACL()
	{
		try{
			String decodedPath = getExecutionPath();
			System.out.println("properties path: " + decodedPath);
			FileReader ir = new FileReader(String.format("%s/acl.data", decodedPath));
			BufferedReader br = new BufferedReader(ir);
			
			String line;
			while( (line = br.readLine()) != null)
			{
				DeniedItem itm = new DeniedItem();
				String[] strItem = line.split("\\s");
				itm.server = strItem[0];
				itm.type = strItem[1];
				acl.add(itm);
			}
			
			br.close();
		}catch(FileNotFoundException ex)
		{
			
		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
	
	private void loadACLTest()
	{
		try{
			String path = httpproxy.HttpProxyMain.class.getProtectionDomain().getCodeSource().getLocation().getPath();
			String decodedPath = URLDecoder.decode(path, "UTF-8");
			System.out.println("properties path: " + decodedPath);
			FileReader ir = new FileReader(String.format("%sacl.data", decodedPath));
			BufferedReader br = new BufferedReader(ir);
			
			String line;
			while( (line = br.readLine()) != null)
			{
				DeniedItem itm = new DeniedItem();
				String[] strItem = line.split("\\s");
				itm.server = strItem[0];
				itm.type = strItem[1];
				acl.add(itm);
			}
			
			br.close();
		}catch(FileNotFoundException ex)
		{
			
		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
	
	private static byte[] altimage;
	public static byte[] getAltImage()
	{
		if(altimage == null)
		{
			String path = httpproxy.HttpProxyMain.class.getProtectionDomain().getCodeSource().getLocation().getPath();
			String decodedPath="";
			try {
				decodedPath = URLDecoder.decode(path, "UTF-8");
			} catch (UnsupportedEncodingException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			System.out.println("properties path: " + decodedPath);
			//FileInputStream fis = new FileInputStream(String.format("%sproxy.properties", decodedPath));
			//FileInputStream fs = new FileInputStream( String.format("%sspeaker.jpeg", HttpProxyMain.getExecutionPath()));
			File f = new File(String.format("%sbtn-gray-bg.png", decodedPath));
			try {
				altimage = new byte[(int)f.length()];
				FileInputStream fs = new FileInputStream( f );
				fs.read(altimage);
				fs.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return altimage;
	}
	
	public static void main(String[] args) 
	{
		HttpProxyMain app = new HttpProxyMain();
	}

}
